package com.example.demoeasyexcelboot.processor;

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.write.handler.RowWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.example.demoeasyexcelboot.annotation.ExcelMerge;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author: FSL
 * @date: 2023/4/12
 * @description: 单元格合并策略(只有相邻相同才合并，导出时可集合排序)，通过registerWriteHandler(new ExcelMergeStrategy(xxx.class))注册
 * 导出的数据量过大会影响性能
 */
public class ExcelMergeStrategy implements RowWriteHandler {

    /**需要合并的列索引*/
    private final List<Integer> mergeColumnIndex = new ArrayList<>();
    /**需要导出的数据结构类*/
    private final Class<?> elementType;

    /**存储表头占用了多少行*/
    private AtomicInteger atomicInteger = new AtomicInteger(0);
    public ExcelMergeStrategy(Class<?> elementType) {
        this.elementType = elementType;
    }

    @Override
    public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) {
        // 标题不做处理
        if (isHead) {
         atomicInteger.incrementAndGet();
         return;
        }
        // 获取当前工作表
        Sheet sheet = writeSheetHolder.getSheet();

        // 初始化需要合并字段的下标
        this.initMergeIndex(writeSheetHolder,atomicInteger);
        // 不能和标题合并
        if (row.getRowNum() < atomicInteger.get()) return;
        // 获取上一行数据,判断是否需要和上一行合并
        Row lastRow = sheet.getRow(row.getRowNum() - 1);
        for (Integer index : mergeColumnIndex){
            Cell curCell = row.getCell(index);
            Cell lastRowCell = lastRow.getCell(index);
            Object culObj = curCell.getCellType() == CellType.STRING ? curCell.getStringCellValue() : curCell.getNumericCellValue();
            Object lastObj = lastRowCell.getCellType() == CellType.STRING ? lastRowCell.getStringCellValue() : lastRowCell.getNumericCellValue();
            if (culObj.equals(lastObj)){
                CellRangeAddress cellAddresses = new CellRangeAddress(row.getRowNum() - 1,row.getRowNum(),index,index);
                sheet.addMergedRegionUnsafe(cellAddresses);
            }
        }
    }

    /**
     * @description: 获取需要合并处理的列
     * @author: FSL
     * @date: 2023/4/13
     * @param writeSheetHolder
     * @return: void
     */
    private void initMergeIndex(WriteSheetHolder writeSheetHolder,AtomicInteger atg) {
        Sheet sheet = writeSheetHolder.getSheet();
        // 获取标题行，如果标题只占一行则为0，否则根据具体的表头设置
        Row titleRow;
        if (atg.get() > 0){
            titleRow = sheet.getRow(atg.get() - 1);
        }else {
            titleRow = sheet.getRow(0);
        }
        // 获取所有属性字段
        Field[] fields = this.elementType.getDeclaredFields();
        for (Field field : fields){
            // 获取ExcelProperty注解，用于获取该字段的列下标
            ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
            if (Objects.isNull(excelProperty)) continue;

            // 获取自定义注解，用于合并单元格
            ExcelMerge excelMerge = field.getAnnotation(ExcelMerge.class);
            if (Objects.isNull(excelMerge)) continue;
            for (int i = 0;i < fields.length;i++){
                Cell cell = titleRow.getCell(i);
                if (Objects.isNull(cell)) continue;
                // 将字段和表头匹配上
                if (excelProperty.value()[excelProperty.value().length -1].equalsIgnoreCase(cell.getStringCellValue())){
                    if (excelMerge.merge()) mergeColumnIndex.add(i);
                }
            }
        }
    }
}
